package com.zx.system.block.service.impl;

import com.alibaba.fastjson2.JSON;
import com.alibaba.fastjson2.JSONObject;
import com.zx.core.context.TenantContextHolder;
import com.zx.core.enums.StatusEnum;
import com.zx.core.wrapper.ListWrapper;
import com.zx.core.wrapper.ResponseWrapper;
import com.zx.redis.block.service.RedisBlockService;
import com.zx.security.block.uitls.SecurityUtils;
import com.zx.security.common.model.LoginUser;
import com.zx.system.block.dao.SysMenuMapper;
import com.zx.system.block.enums.*;
import com.zx.system.block.mapstruct.MenuMapStructMapper;
import com.zx.system.block.model.SysMenu;
import com.zx.system.block.param.MenuParam;
import com.zx.system.block.service.ISysMenuService;
import com.zx.system.block.utils.SystemNoUtils;
import com.zx.system.block.vo.MetaVO;
import com.zx.system.block.vo.RouterVO;
import com.zx.system.block.vo.SysMenuVO;
import com.zx.system.block.vo.TreeVO;
import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.springframework.security.core.Authentication;
import org.springframework.security.oauth2.jwt.Jwt;
import org.springframework.stereotype.Service;

import java.time.LocalDateTime;
import java.util.*;
import java.util.stream.Collectors;

/**
 * <p>
 * description: 业务层菜单服务实现 <br>
 * create: 2024-08-24 11:50
 * </p>
 *
 * @author zhou  xun
 */
@Slf4j
@Service
@RequiredArgsConstructor
public class SysMenuServiceImpl implements ISysMenuService {
    private final SysMenuMapper sysMenuMapper;
    private final RedisBlockService redisBlockService;

    /**
     * 根据用户ID查询菜单树信息
     *
     * @return 菜单列表
     */
    @Override
    public List<RouterVO> selectMenuTreeByUserId() {
        Authentication authentication = SecurityUtils.getAuthentication();
        Jwt jwt = (Jwt) authentication.getPrincipal();
        String uuid = jwt.getClaim("userId");
        String redisKey = "login_userId:" + uuid;
        // 从Redis获取缓存的用户信息
        Object cacheObject = redisBlockService.getCacheObject(redisKey);
        LoginUser loginUser = JSON.parseObject(((JSONObject) cacheObject).toJSONString(), LoginUser.class);
        Set<String> roles = loginUser.getRoles();
        List<SysMenu> menus = sysMenuMapper.selectMenuTreeByUserId(loginUser.getId());
        //转换为前端需要的vo对象
        List<RouterVO> routerVOList = new ArrayList<>();
        if (null != menus && !menus.isEmpty()) {
            //移除列表中禁用的菜单和非路由信息
            menus = menus.stream().filter(sysMenu -> MenuTypeEnum.MENU.getCode().equals(sysMenu.getMenuType()) && StatusEnum.ENABLE.getCode().equals(sysMenu.getStatus())).toList();
            menus.forEach(sysMenu -> {
                RouterVO routerVo = convertToRouterVo(sysMenu);
                routerVOList.add(routerVo);
            });
            routerVOList.forEach(routerVO -> {
                List<RouterVO> children = routerVOList.stream().filter(item -> routerVO.getMeta().getId().equals(item.getMeta().getParentId())).collect(Collectors.toList());
                if (!children.isEmpty()) {
                    routerVO.setChildren(children);
                }
            });
            // 使用迭代器移除元素
            routerVOList.removeIf(routerVO -> routerVO.getMeta().getParentId() != null);
        }
        return routerVOList;
    }

    /**
     * 查询菜单列表
     *
     * @param menuParam 菜单参数
     * @return {@link ListWrapper <SysMenu>}
     * @author zhou  xun
     * @since 2024-12-15
     */
    @Override
    public ListWrapper<SysMenu> selectMenuList(MenuParam menuParam) {
        ListWrapper<SysMenu> result = new ListWrapper<>();
        SysMenu sysMenu = MenuMapStructMapper.INSTANCE.menuParamToSysMenu(menuParam);
        List<SysMenu> sysMenuList = sysMenuMapper.selectSysMenuList(sysMenu);
        if (null != sysMenuList && !sysMenuList.isEmpty()) {
            result.setData(sysMenuList);
        }
        return result;
    }

    /**
     * 新增菜单
     *
     * @param menuParam 菜单参数
     * @return {@link ResponseWrapper}
     * @author zhou  xun
     * @since 2024-12-21
     */
    @Override
    public ResponseWrapper addMenu(MenuParam menuParam) {
        ResponseWrapper result = new ResponseWrapper();
        try {
            // 验证菜单状态
            StatusEnum statusEnum = StatusEnum.getEnumByCode(menuParam.getStatus());
            if (null == statusEnum) {
                result.fail("传入的菜单状态错误!");
                return result;
            }
            //验证菜单类型
            MenuTypeEnum menuTypeEnum = MenuTypeEnum.getEnumByCode(menuParam.getMenuType());
            if (null == menuTypeEnum) {
                result.fail("传入的菜单类型错误!");
                return result;
            }
            if (menuTypeEnum.getCode().equals(MenuTypeEnum.MENU.getCode())) {
                AffixEnum affixEnum = AffixEnum.getEnumByCode(menuParam.getAffix());
                if (null == affixEnum) {
                    result.fail("传入的菜单附加标签视图参数错误!");
                    return result;
                }
                AlwaysShowEnum alwaysShowEnum = AlwaysShowEnum.getEnumByCode(menuParam.getAlwaysShow());
                if (null == alwaysShowEnum) {
                    result.fail("传入的显示根菜单参数错误!");
                    return result;
                }
                BreadcrumbEnum breadcrumbEnum = BreadcrumbEnum.getEnumByCode(menuParam.getBreadcrumb());
                if (null == breadcrumbEnum) {
                    result.fail("传入的菜单显示面包屑参数错误!");
                    return result;
                }
                HiddenEnum hiddenEnum = HiddenEnum.getEnumByCode(menuParam.getHidden());
                if (null == hiddenEnum) {
                    result.fail("传入的菜单隐藏参数错误!");
                    return result;
                }
                ComponentCacheEnum componentCacheEnum = ComponentCacheEnum.getEnumByCode(menuParam.getComponentCache());
                if (null == componentCacheEnum) {
                    result.fail("传入的菜单组件缓存参数错误!");
                    return result;
                }
            }
            if (null != menuParam.getParentId()) {
                // 验证父级菜单是否存在
                SysMenu selectByParentId = sysMenuMapper.selectByPrimaryKey(menuParam.getParentId());
                if (null == selectByParentId) {
                    result.fail("传入的父级菜单信息不存在!");
                    return result;
                }

            }
            //验证菜单名称唯一性
            List<SysMenu> sysMenuList = sysMenuMapper.selectSysMenuByParentId(menuParam.getParentId());
            if (null != sysMenuList && !sysMenuList.isEmpty()) {
                if (sysMenuList.stream().anyMatch(sysMenu -> sysMenu.getName().equals(menuParam.getName()))) {
                    result.fail("已存在相同菜单名称!");
                    return result;
                }
            }
            // 获取完整的菜单列表用于后续验证
            List<SysMenu> allSysMenuList = sysMenuMapper.selectMenuTreeAll(TenantContextHolder.getTenantId());

            //验证路由名称唯一性
            if (null != allSysMenuList && !allSysMenuList.isEmpty()) {
                if (allSysMenuList.stream().anyMatch(sysMenu -> sysMenu.getRouteName() != null && sysMenu.getRouteName().equals(menuParam.getRouteName()))) {
                    result.fail("已存在相同路由名称!");
                    return result;
                }
            }
            //验证组件名称唯一性
            if (null != allSysMenuList && !allSysMenuList.isEmpty()) {
                if (allSysMenuList.stream().anyMatch(sysMenu -> sysMenu.getComponentName() != null && sysMenu.getComponentName().equals(menuParam.getComponentName()))) {
                    result.fail("已存在相同组件名称!");
                    return result;
                }
            }
            SysMenu sysMenu = MenuMapStructMapper.INSTANCE.menuParamToSysMenu(menuParam);
            // 设置id
            sysMenu.setId(SystemNoUtils.generateSystemId());
            sysMenu.setCreateBy(SecurityUtils.getUserId());
            sysMenu.setCreateTime(LocalDateTime.now());
            sysMenuMapper.insert(sysMenu);
        } catch (Exception e) {
            log.error("新增菜单时发生错误", e);
            result.fail("新增菜单时发生错误: " + e.getMessage());
        }
        return result;
    }

    /**
     * 编辑菜单
     *
     * @param menuParam 菜单参数
     * @return {@link ResponseWrapper}
     * @author zhou  xun
     * @since 2024-12-21
     */
    @Override
    public ResponseWrapper editMenu(MenuParam menuParam) {
        ResponseWrapper result = new ResponseWrapper();
        try {
            // 验证菜单状态
            StatusEnum statusEnum = StatusEnum.getEnumByCode(menuParam.getStatus());
            if (null == statusEnum) {
                result.fail("传入的菜单状态错误!");
                return result;
            }
            //验证菜单类型
            MenuTypeEnum menuTypeEnum = MenuTypeEnum.getEnumByCode(menuParam.getMenuType());
            if (null == menuTypeEnum) {
                result.fail("传入的菜单类型错误!");
                return result;
            }
            if (menuTypeEnum.getCode().equals(MenuTypeEnum.MENU.getCode())) {
                AffixEnum affixEnum = AffixEnum.getEnumByCode(menuParam.getAffix());
                if (null == affixEnum) {
                    result.fail("传入的菜单附加标签视图参数错误!");
                    return result;
                }
                AlwaysShowEnum alwaysShowEnum = AlwaysShowEnum.getEnumByCode(menuParam.getAlwaysShow());
                if (null == alwaysShowEnum) {
                    result.fail("传入的显示根菜单参数错误!");
                    return result;
                }
                BreadcrumbEnum breadcrumbEnum = BreadcrumbEnum.getEnumByCode(menuParam.getBreadcrumb());
                if (null == breadcrumbEnum) {
                    result.fail("传入的菜单显示面包屑参数错误!");
                    return result;
                }
                HiddenEnum hiddenEnum = HiddenEnum.getEnumByCode(menuParam.getHidden());
                if (null == hiddenEnum) {
                    result.fail("传入的菜单隐藏参数错误!");
                    return result;
                }
                ComponentCacheEnum componentCacheEnum = ComponentCacheEnum.getEnumByCode(menuParam.getComponentCache());
                if (null == componentCacheEnum) {
                    result.fail("传入的菜单组件缓存参数错误!");
                    return result;
                }
            }
            // 验证菜单是否存在
            SysMenu selectByPrimaryKey = sysMenuMapper.selectByPrimaryKey(menuParam.getId());
            if (null == selectByPrimaryKey) {
                result.fail("传入的菜单信息不存在!");
                return result;
            }
            //验证菜单名称唯一性
            List<SysMenu> sysMenuList = sysMenuMapper.selectSysMenuByParentId(menuParam.getParentId());
            if (null != sysMenuList && !sysMenuList.isEmpty()) {
                if (sysMenuList.stream().anyMatch(sysMenu -> sysMenu.getName().equals(menuParam.getName())
                        && !sysMenu.getId().equals(menuParam.getId()))) {
                    result.fail("已存在相同菜单名称!");
                    return result;
                }
            }
            // 获取完整的菜单列表用于后续验证
            List<SysMenu> allSysMenuList = sysMenuMapper.selectMenuTreeAll(TenantContextHolder.getTenantId());

            //验证路由名称唯一性
            if (null != allSysMenuList && !allSysMenuList.isEmpty()) {
                if (allSysMenuList.stream().anyMatch(sysMenu -> sysMenu.getRouteName() != null && sysMenu.getRouteName().equals(menuParam.getRouteName())
                        && !sysMenu.getId().equals(menuParam.getId()))) {
                    result.fail("已存在相同路由名称!");
                    return result;
                }
            }
            //验证组件名称唯一性
            if (null != allSysMenuList && !allSysMenuList.isEmpty()) {
                if (allSysMenuList.stream().anyMatch(sysMenu -> sysMenu.getComponentName() != null && sysMenu.getComponentName().equals(menuParam.getComponentName())
                        && !sysMenu.getId().equals(menuParam.getId()))) {
                    result.fail("已存在相同组件名称!");
                    return result;
                }
            }
            SysMenu sysMenu = MenuMapStructMapper.INSTANCE.menuParamToSysMenu(menuParam);
            sysMenu.setUpdateBy(SecurityUtils.getUserId());
            sysMenu.setUpdateTime(LocalDateTime.now());
            sysMenuMapper.updateByPrimaryKeySelective(sysMenu);
        } catch (Exception e) {
            log.error("编辑菜单时发生错误", e);
            result.fail("编辑菜单时发生错误: " + e.getMessage());
        }
        return result;
    }

    /**
     * 修改菜单状态
     *
     * @param id     菜单ID
     * @param status 菜单状态
     * @return {@link ResponseWrapper}
     * @author zhou  xun
     * @since 2024-12-21
     */
    @Override
    public ResponseWrapper editMenuStatus(String id, Integer status) {
        ResponseWrapper result = new ResponseWrapper();
        try {
            // 验证菜单状态
            StatusEnum statusEnum = StatusEnum.getEnumByCode(status);
            if (null == statusEnum) {
                result.fail("传入的菜单状态错误!");
                return result;
            }
            // 验证菜单是否存在
            SysMenu selectByPrimaryKey = sysMenuMapper.selectByPrimaryKey(id);
            if (null == selectByPrimaryKey) {
                result.fail("传入的菜单信息不存在!");
                return result;
            }
            SysMenu sysMenu = new SysMenu();
            sysMenu.setId(id);
            sysMenu.setStatus(status);
            sysMenu.setUpdateBy(SecurityUtils.getAuthentication().getName());
            sysMenu.setUpdateTime(LocalDateTime.now());
            sysMenuMapper.updateByPrimaryKeySelective(sysMenu);
        } catch (Exception e) {
            log.error("编辑菜单状态时发生错误", e);
            result.fail("编辑菜单状态时发生错误: " + e.getMessage());
        }
        return result;
    }

    /**
     * 删除菜单
     *
     * @param menuId 菜单ID
     * @return {@link ResponseWrapper}
     * @author zhou  xun
     * @since 2024-12-21
     */
    @Override
    public ResponseWrapper deleteMenu(String menuId) {
        ResponseWrapper result = new ResponseWrapper();
        try {
            // 验证部门是否存在
            SysMenu selectByPrimaryKey = sysMenuMapper.selectByPrimaryKey(menuId);
            if (null == selectByPrimaryKey) {
                result.fail("传入的部门信息不存在!");
                return result;
            }
            List<SysMenu> sysMenuList = sysMenuMapper.selectSysMenuByParentId(menuId);
            if (sysMenuList != null && !sysMenuList.isEmpty()) {
                result.fail("该菜单下存在子菜单，无法删除!");
                return result;
            }
            sysMenuMapper.deleteByPrimaryKey(menuId);
        } catch (Exception e) {
            log.error("删除菜单时发生错误", e);
            result.fail("删除菜单时发生错误: " + e.getMessage());
        }
        return result;
    }

    /**
     * 获取菜单树
     *
     * @param menuParam 菜单树
     * @return {@link ListWrapper< TreeVO >}
     * @author zhou  xun
     * @since 2024-12-25
     */
    @Override
    public ListWrapper<TreeVO> getMenuTree(MenuParam menuParam) {
        ListWrapper<TreeVO> result = new ListWrapper<>();
        SysMenu sysMenu = MenuMapStructMapper.INSTANCE.menuParamToSysMenu(menuParam);
        List<SysMenu> sysMenuList = sysMenuMapper.selectSysMenuList(sysMenu);
        List<TreeVO> treeVoList = convertToTreeVo(sysMenuList);
        result.setData(treeVoList);
        return result;
    }

    /**
     * 获取菜单信息Map 用于菜单信息匹配
     *
     * @return 包含菜单标识作为键，{@link SysMenu} 对象作为值的映射{@code Map<String, SysMenu>}
     * @author zhou  xun
     * @since 2024-12-28
     */
    @Override
    public Map<String, SysMenu> getMenu() {
        Map<String, SysMenu> map = new HashMap<>();
        List<SysMenu> sysMenuList = sysMenuMapper.selectSysMenuList(null);
        if (null != sysMenuList && !sysMenuList.isEmpty()) {
            //将列表转换为 Map
            for (SysMenu sysMenu : sysMenuList) {
                map.putIfAbsent(sysMenu.getId(), sysMenu);
            }
        }
        return map;
    }

    /**
     * 查询菜单信息
     *
     * @param userId 用户id
     * @return {@link ListWrapper<SysMenu>}
     * @author zhou  xun
     * @since 2024-12-25
     */
    @Override
    public ListWrapper<SysMenu> selectSysMenuInfos(String userId) {
        ListWrapper<SysMenu> result = new ListWrapper<>();
        try {
            List<SysMenu> sysMenuList = sysMenuMapper.selectSysMenuByUserId(userId);
            if (!sysMenuList.isEmpty()) {
                result.setData(sysMenuList);
            }
        } catch (Exception e) {
            log.error("查询权限时发生错误", e);
            result.fail("查询权限时发生错误: " + e.getMessage());
        }
        return result;
    }

    @Override
    public ListWrapper<SysMenuVO> selectMenuVOList(MenuParam menuParam) {
        // 获取菜单列表
        ListWrapper<SysMenu> listWrapper = selectMenuList(menuParam);

        // 验证请求是否成功或数据是否为空
        if (listWrapper.verifyFail()) {
            ListWrapper<SysMenuVO> result = new ListWrapper<>();
            result.fail(listWrapper.getMsg());
            return result;
        }

        if (null == listWrapper.getData() || listWrapper.getData().isEmpty()) {
            ListWrapper<SysMenuVO> result = new ListWrapper<>();
            result.setData(Collections.emptyList());
            return result;
        }

        // 获取菜单信息用于查询父菜单名称
        Map<String, SysMenu> menuMap = getMenu();

        // 转换并处理数据
        List<SysMenuVO> processedData = listWrapper.getData().stream()
                .map(item -> {
                    // 使用MapStruct进行基础属性转换和描述性字段设置
                    SysMenuVO sysMenuVO = MenuMapStructMapper.INSTANCE.sysMenuToSysMenuVO(item);

                    // 设置父菜单名称
                    String parentId = item.getParentId();
                    if (null != parentId && !parentId.isEmpty()) {
                        SysMenu parentMenu = menuMap.get(parentId);
                        if (null != parentMenu) {
                            sysMenuVO.setParentName(parentMenu.getName());
                        }
                    }

                    return sysMenuVO;
                })
                .collect(Collectors.toList());

        // 创建结果包装对象并设置数据
        ListWrapper<SysMenuVO> result = new ListWrapper<>();
        result.setData(processedData);
        return result;
    }

    private List<TreeVO> convertToTreeVo(List<SysMenu> sysMenuList) {
        //转换为前端需要的vo对象
        List<TreeVO> treeVOList = new ArrayList<>();
        if (!sysMenuList.isEmpty()) {
            sysMenuList.forEach(sysMenu -> {
                TreeVO treeVo = new TreeVO();
                if (null != sysMenu.getId() && !sysMenu.getId().isEmpty()) {
                    treeVo.setId(sysMenu.getId());
                }
                if (null != sysMenu.getParentId() && !sysMenu.getParentId().isEmpty()) {
                    treeVo.setParentId(sysMenu.getParentId());
                }
                if (null != sysMenu.getName() && !sysMenu.getName().isEmpty()) {
                    treeVo.setName(sysMenu.getName());
                }
                treeVOList.add(treeVo);
            });
            treeVOList.forEach(treeVo -> {
                List<TreeVO> children = treeVOList.stream()
                        .filter(item -> treeVo.getId().equals(item.getParentId()))
                        .collect(Collectors.toList());
                if (!children.isEmpty()) {
                    treeVo.setChildren(children);

                }
            });
            // 使用迭代器移除元素
            treeVOList.removeIf(treeVo -> treeVo.getParentId() != null);
        }
        return treeVOList;
    }

    private RouterVO convertToRouterVo(SysMenu sysMenu) {
        RouterVO routerVo = new RouterVO();
        routerVo.setPath(sysMenu.getUrl());
        routerVo.setName(sysMenu.getName());
        if (sysMenu.getRedirect() != null && !sysMenu.getRedirect().isEmpty()) {
            routerVo.setRedirect(sysMenu.getRedirect());
        }
        if (sysMenu.getComponent() != null && !sysMenu.getComponent().isEmpty()) {
            routerVo.setComponent(sysMenu.getComponent());
        }
        MetaVO metaVo = new MetaVO();
        metaVo.setId(sysMenu.getId());
        if (sysMenu.getParentId() != null && !sysMenu.getParentId().isEmpty()) {
            metaVo.setParentId(sysMenu.getParentId());
        }

        HiddenEnum hiddenEnum = HiddenEnum.getEnumByCode(sysMenu.getHidden());
        if (hiddenEnum != null) {
            metaVo.setHidden(hiddenEnum.isBoolValue());
            metaVo.setHiddenDesc(hiddenEnum.getDesc());
        }
        if (sysMenu.getComponentName() != null && !sysMenu.getComponentName().isEmpty()) {
            metaVo.setComponentName(sysMenu.getComponentName());
        }
        AlwaysShowEnum alwaysShowEnum = AlwaysShowEnum.getEnumByCode(sysMenu.getAlwaysShow());
        if (alwaysShowEnum != null) {
            metaVo.setAlwaysShow(alwaysShowEnum.isBoolValue());
            metaVo.setAlwaysShowDesc(alwaysShowEnum.getDesc());
        }
        if (sysMenu.getTitle() != null && !sysMenu.getTitle().isEmpty()) {
            metaVo.setTitle(sysMenu.getTitle());
        }
        if (sysMenu.getHref() != null && !sysMenu.getHref().isEmpty()) {
            metaVo.setHref(sysMenu.getHref());
        }
        if (sysMenu.getIcon() != null && !sysMenu.getIcon().isEmpty()) {
            metaVo.setIcon(sysMenu.getIcon());
        }

        ComponentCacheEnum componentCacheEnum = ComponentCacheEnum.getEnumByCode(sysMenu.getComponentCache());
        if (componentCacheEnum != null) {
            metaVo.setComponentCache(componentCacheEnum.isBoolValue());
            metaVo.setComponentCacheDesc(componentCacheEnum.getDesc());
        }
        AffixEnum affixEnum = AffixEnum.getEnumByCode(sysMenu.getAffix());
        if (affixEnum != null) {
            metaVo.setAffix(affixEnum.isBoolValue());
            metaVo.setAffixDesc(affixEnum.getDesc());
        }
        BreadcrumbEnum breadcrumbEnum = BreadcrumbEnum.getEnumByCode(sysMenu.getBreadcrumb());
        if (breadcrumbEnum != null) {
            metaVo.setBreadcrumb(breadcrumbEnum.isBoolValue());
            metaVo.setBreadcrumbDesc(breadcrumbEnum.getDesc());
        }
        if (sysMenu.getActiveMenu() != null && !sysMenu.getActiveMenu().isEmpty()) {
            metaVo.setActiveMenu(sysMenu.getActiveMenu());
        }
        routerVo.setMeta(metaVo);
        return routerVo;
    }
}
